package local.pt.iscte.dcti.pa.utils;

import java.util.List;
import java.util.ArrayList;

import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IConfigurationElement;
import org.eclipse.core.runtime.Platform;
import org.eclipse.ui.activities.NotDefinedException;

import com.eexcel.workbench.IFormula;

/**
 * Defines the manager for all the plug-in extensions
 * @author Simão Fernandes
 * @version %I%, %G%
 * @since 1.0
 */
public class ExtensionManager {

	/**
	 * Extension Id
	 */
	private static final String IFORMULA_ID = "com.eexcel.workbench.formula";
	/**
	 * List of extension contributors
	 */
	private List<FormulaContributor> formulaContributors;

	/**
	 * Default constructor
	 */
	public ExtensionManager() {
		formulaContributors = new ArrayList<FormulaContributor>();

		// TODO handle repeated function names
		IConfigurationElement[] allConfigElements = Platform
				.getExtensionRegistry()
				.getConfigurationElementsFor(IFORMULA_ID);

		FormulaContributor fc = null;

		for (IConfigurationElement ice : allConfigElements) {

			fc = new FormulaContributor();
			fc.setName(ice.getDeclaringExtension().getContributor().getName());

			Object o = null;
			try {
				o = ice.createExecutableExtension("class");
			} catch (CoreException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}

			if (o != null && o instanceof IFormula) {
				fc.setExecutableExtension((IFormula) o);
				getFormulaNames((IFormula) o, fc);
			}

			formulaContributors.add(fc);
		}
	}

	// PUBLIC METHODS: start

	/**
	 * Applies the given function to the given operand
	 * 
	 * @param function
	 *            Function to be applied to the operand
	 * @param operand
	 *            operand apply the formula
	 * @return result obtained
	 */
	public int applyFunction(String function, int operand) {
		return this.getFormulaContributorByFunction(function).applyFunction(
				function, operand);
	}

	// GETTERS & SETTERS: start
	/**
	 * Gets the list of the formula contributors
	 * 
	 * @return List of the formula contributors
	 */
	public List<FormulaContributor> getFormulaContributors() {
		return formulaContributors;
	}

	/**
	 * Sets the list of the formula contributors
	 * 
	 * @param formulacontributors
	 *            List of the formula contributors
	 */
	public void setFormulaContributors(
			List<FormulaContributor> formulacontributors) {
		this.formulaContributors = formulacontributors;
	}

	// GETTERS & SETTERS: end

	/**
	 * Checks if a given string is a method name
	 * 
	 * @param qualifyingString
	 * @return True if it is a method name, otherwise returns false
	 */
	public boolean isExtensionMethod(String qualifyingString) {
		for (FormulaContributor fc : formulaContributors) {
			for (String function : fc.getFunctions()) {
				if (qualifyingString.startsWith(function)) {
					return true;
				}
			}
		}
		return false;
	}

	// PUBLIC METHODS: end

	// PRIVATE METHODS: start
	/**
	 * Gets a Formula contributor reference by a given function
	 * 
	 * @param function
	 *            Function
	 * @return Formula contributor reference
	 */
	private FormulaContributor getFormulaContributorByFunction(String function) {
		for (FormulaContributor fc : formulaContributors) {
			if (fc.getFunctions().contains(function)) {
				return fc;
			}
		}
		return null;
	}

	/**
	 * Gets the names of the formulas that the extension provides
	 * 
	 * @param formula
	 *            Formula to get the name
	 * @param fc
	 *            Formula contributor instance to store the name
	 */
	private void getFormulaNames(final IFormula formula,
			final FormulaContributor fc) {
		org.eclipse.core.runtime.ISafeRunnable runnable = new org.eclipse.core.runtime.ISafeRunnable() {
			@Override
			public void handleException(Throwable exception) {
				System.out.println("Exception in client");
			}

			@Override
			public void run() throws Exception {
				String[] functions = formula.getFunctions();
				fc.setFunctions(java.util.Arrays.asList(functions));
			}
		};
		org.eclipse.core.runtime.SafeRunner.run(runnable);
	}

	// PRIVATE METHODS: end
}
